package eip.chapter1.example;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.stream.XMLStreamException;


import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.om.xpath.AXIOMXPath;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;
import org.jaxen.JaxenException;

public class CalcServiceFacade {
	
	private final static String NS = "http://www.companyA.org/salary";
	private final static String RESPONSE ="response";
	private final static String PERSONS ="persons";
	private final static String RESPONSEPERSON ="responsePerson";
	private final static String FIRSTNAME ="firstName";
	private final static String LASTNAME ="lastName";
	private final static String SALARY ="salary";
	private final static String STATUS ="status";
	private final static String ATT_TOTAL ="total";

	
	private CalcService calcService = new CalcService();
	
	/**
	 * Called from synapse. This method calls the CalcService and return the
	 * result.
	 * 
	 * @param element
	 * @throws JaxenException 
	 * @throws IOException 
	 * @throws XMLStreamException 
	 */
	public OMElement calculate(OMElement element) throws JaxenException, IOException, XMLStreamException {		
		List<CalcResponse> response = doCalculations(element);
		Document doc = transformCalculationResponses(response);
		ByteArrayOutputStream bOut = new ByteArrayOutputStream();
		XMLWriter writer = new XMLWriter();
		writer.setOutputStream(bOut);
		writer.write(doc);
		StAXOMBuilder builder = new StAXOMBuilder(new ByteArrayInputStream(bOut.toByteArray()));
		return builder.getDocumentElement();
	}
	
    /**
	 * @param element
	 * @return
	 * @throws JaxenException
	 */
	private List<CalcResponse> doCalculations(OMElement element) throws JaxenException {
		AXIOMXPath path = new AXIOMXPath("//person");
		path.addNamespace("",NS);
		List nodes = path.selectNodes(element);
		List<CalcResponse> result = new ArrayList<CalcResponse>(nodes.size());
		for (Object object : nodes) {
			path = new AXIOMXPath("firstName");
			path.addNamespace("",NS);
			String firstName = ((OMElement)path.selectSingleNode(object)).getText();
			path = new AXIOMXPath("lastName");
			path.addNamespace("",NS);
			String lastName = ((OMElement)path.selectSingleNode(object)).getText();
			path = new AXIOMXPath("salary/base/@value");
			path.addNamespace("",NS);
			path.evaluate(object).toString();
			String value = ((OMAttribute)path.selectSingleNode(object)).getAttributeValue();
			path = new AXIOMXPath("salary/provision/@percentage");
			path.addNamespace("",NS);		
			String percentage = ((OMAttribute)path.selectSingleNode(object)).getAttributeValue();
			path = new AXIOMXPath("salary/provision/@sum");
			path.addNamespace("",NS);		
			path.evaluate(object).toString();
			String sum = ((OMAttribute)path.selectSingleNode(object)).getAttributeValue();
			
			double calc = calcService.calculateSalary(new Double(value).doubleValue(),
					new Double(sum).doubleValue(), Float.parseFloat(percentage));
			
			CalcResponse response = new CalcResponse();
			response.setFirstName(firstName);
			response.setLastName(lastName);
			response.setTotal(calc);
			response.setStatus("OK");
			result.add(response);
		}
		
		return result;
	}
	
	
	private Document transformCalculationResponses(List<CalcResponse> responses) {
		    Document result = DocumentHelper.createDocument();
		    Element root = result.addElement(RESPONSE,NS);
		    // root.addNamespace("cmpa", NS);
		    Element persons = root.addElement(PERSONS,NS);
		    
		    for (CalcResponse response : responses) {
			      Element person = persons.addElement(RESPONSEPERSON,NS);
			      person.addElement(STATUS,NS).setText(response.getStatus());
			      person.addElement(FIRSTNAME,NS).setText(response.getFirstName());
			      person.addElement(LASTNAME,NS).setText(response.getLastName());
			      person.addElement(SALARY,NS).addAttribute(ATT_TOTAL,Double.toString(response.getTotal()));
			}
		    return result;
		  }
}
